package com.wang.cloud.manage.service.manage;

import cn.hutool.core.util.ObjectUtil;
import com.wang.cloud.common.core.constants.Constants;
import com.wang.cloud.common.core.exception.ServiceException;
import com.wang.cloud.manage.convert.MenuConvertor;
import com.wang.cloud.manage.domain.co.MenuAddCo;
import com.wang.cloud.manage.domain.co.MenuUpdateCo;
import com.wang.cloud.manage.domain.co.MenuUpdateStatusCo;
import com.wang.cloud.manage.domain.entity.MenuEntity;
import com.wang.cloud.manage.enums.MenuTypeEnums;
import com.wang.cloud.manage.service.IMenuService;
import com.wang.cloud.manage.service.IRoleMenuRelationService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @author wangye
 * @date 2023/7/17 0017
 */
@Slf4j
@Service
public class MenuManageService {
    /**
     * 路由支持的最大层级
     */
    private static final int MAX_LV = 5;
    /**
     * 所属上级路由的id集合 数据库支持的最大长度
     */
    private static final int ANCESTORS_MAX_LENGTH = 100;

    @Resource
    private IMenuService menuService;
    @Resource
    private IRoleMenuRelationService roleMenuRelationService;
    @Resource
    private MenuConvertor menuConvertor;

    @Transactional(rollbackFor = Exception.class)
    public Long addMenu(MenuAddCo co) {
        checkTypeAndPath(co.getParentId(), null, co.getMenuType(), co.getPath());
        MenuEntity parentMenu = checkParentAndGetInfo(co.getParentId());
        int lv = generateLv(parentMenu);
        String ancestors = generateAncestors(parentMenu);
        MenuEntity newMenu = menuConvertor.addCoToEntity(co);
        newMenu.setLv(lv);
        newMenu.setAncestors(ancestors);
        menuService.save(newMenu);
        menuService.updateChildrenMenuNum(newMenu.getParentId());
        return newMenu.getId();
    }

    private void checkTypeAndPath(Long parentId, Long menuId, String menuType, String path) {
        MenuTypeEnums typeEnums = MenuTypeEnums.getEnum(menuType);
        if (Objects.isNull(typeEnums)) {
            throw new ServiceException("非法的路由类型");
        }
        switch (typeEnums) {
            case C:
                if (ObjectUtil.isEmpty(path)) {
                    throw new ServiceException("请输入路由地址");
                }
                break;
            case F:
                if (Objects.isNull(parentId) || Objects.equals(0L, parentId)) {
                    throw new ServiceException("按钮必须要有上级路由");
                }
                if (Objects.nonNull(menuId) && menuService.hasSubMenu(menuId, null)) {
                    throw new ServiceException("存在下级路由，不能修改为按钮");
                }
                break;
            default:
                ;
        }
        if (menuService.pathIsRepeat(path, menuId)) {
            throw new ServiceException("路由地址已存在");
        }
    }

    private MenuEntity checkParentAndGetInfo(Long menuId) {
        /**
         * menuId = 0 表示的是这个站点的根节点
         */
        if (Objects.isNull(menuId) || Objects.equals(0L, menuId)) {
            menuId = 0L;
            // 构造根节点信息
            MenuEntity rootMenu = new MenuEntity();
            rootMenu.setId(menuId);
            rootMenu.setAncestors("");
            rootMenu.setLv(0);
            return rootMenu;
        }

        MenuEntity parentMenu = menuService.getById(menuId);
        if (Objects.isNull(parentMenu)) {
            throw new ServiceException("上级路由不存在");
        }
        if (MenuTypeEnums.F.getType()
                .equals(parentMenu.getMenuType())) {
            throw new ServiceException("上级路由不能是按钮类型");
        }
        return parentMenu;
    }

    private int generateLv(MenuEntity parentChannelInfo) {
        int lv = parentChannelInfo.getLv() + 1;
        if (lv > MAX_LV) {
            throw new ServiceException("路由层级不能超过" + MAX_LV + "层");
        }
        return lv;
    }

    private String generateAncestors(MenuEntity parentChannelInfo) {
        if (Objects.equals(parentChannelInfo.getId(), 0L)) {
            return "0";
        }
        String ancestors = parentChannelInfo.getAncestors() + "," + parentChannelInfo.getId();
        if (ancestors.length() > ANCESTORS_MAX_LENGTH) {
            throw new ServiceException("所属上级路由的id集合过长！请联系服务开发者");
        }
        return ancestors;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean updateMenu(MenuUpdateCo co) {
        MenuEntity oldInfo = menuService.getById(co.getId());
        if (Objects.isNull(oldInfo)) {
            throw new ServiceException("路由不存在");
        }
        checkStatus(co.getId(), co.getStatus());
        checkTypeAndPath(oldInfo.getParentId(), oldInfo.getId(), co.getMenuType(), co.getPath());
        MenuEntity menuEntity = menuConvertor.updateCoToEntity(co);
        return menuService.updateById(menuEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean updateMenuStatus(MenuUpdateStatusCo co) {
        MenuEntity oldInfo = menuService.getById(co.getId());
        if (Objects.isNull(oldInfo)) {
            throw new ServiceException("路由不存在");
        }
        if (Objects.equals(co.getStatus(), oldInfo.getStatus())) {
            return Boolean.FALSE;
        }
        checkStatus(co.getId(), co.getStatus());
        MenuEntity updateInfo = new MenuEntity();
        updateInfo.setId(co.getId());
        updateInfo.setStatus(co.getStatus());
        return menuService.updateById(updateInfo);
    }

    private void checkStatus(Long menuId, String status) {
        // 禁用菜单时
        if (Objects.equals(status, Constants.DISABLE)) {
            // 需要判断下级菜单都已禁用
            if (menuService.hasSubMenu(menuId, Constants.ENABLE)) {
                throw new ServiceException("存在启用的下级路由，禁止停用");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void delMenu(Long menuId) {
        MenuEntity entity = menuService.getById(menuId);
        if (Objects.isNull(entity)) {
            return;
        }
        if (menuService.hasSubMenu(menuId, null)) {
            throw new ServiceException("存在下级路由，禁止删除");
        }
        menuService.del(menuId);

        menuService.updateChildrenMenuNum(entity.getParentId());
        // 删除-角色-菜单-关系
        roleMenuRelationService.delByMenuId(menuId);
    }
}
